package br.com.spam.pipeline.core;

import java.util.ArrayList;
import java.util.List;

import br.com.spam.pipeline.instruction.Instruction;
import br.com.spam.pipeline.instruction.r.NOP;

public class Processor
{

	private static final int nRegisters = 32;

	private int currentClock = 0;
	private final Register PC = new Register("PC", 0);
	private int completedInstructions = 0;
	private final List<Register> registers = new ArrayList<Register>();
	private final PreditorDesvio preditorDesvio = new PreditorDesvio();
	private final PipelineSimulator owner;

	public Processor(PipelineSimulator owner)
	{
		this.owner = owner;
		this.setUpRegisters();
	}

	public int getRegisterValue(int address)
	{
		return this.registers.get(address).getCorrectValue();
	}

	public PreditorDesvio preditorDesvio()
	{
		return this.preditorDesvio;
	}

	public Register getRegister(int address)
	{
		return this.registers.get(address);
	}

	public Iterable<Register> enumerateRegisters()
	{
		return this.registers;
	}

	private void setUpRegisters()
	{
		this.registers.clear();

		for (int i = 0; i < nRegisters; i++)
		{
			this.registers.add(new Register("R" + i));
		}
	}

	public void clockUp()
	{
		this.currentClock += 1;
		this.PC.clockUp();

		for (Register register : this.registers)
		{
			register.clockUp();
		}
	}

	public float getProdutivity()
	{
		if (this.currentClock == 0)
			return 0;
		return ((float) this.completedInstructions) / this.currentClock;
	}

	public Register getPC()
	{
		return this.PC;
	}

	public int getPCRegardlessOfItsState()
	{
		return this.PC.getPersistedValue();
	}

	public int getCurrentClock()
	{
		return this.currentClock;
	}

	public int getCompletedInstructions()
	{
		return this.completedInstructions;
	}

	public void completeInstruction(Instruction instruction)
	{
		if (!(instruction instanceof NOP))
			this.completedInstructions++;
	}

	public PipelineSimulator getPipelineSimulator()
	{
		return this.owner;
	}
}
